package com.ruoyi.common;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.ruoyi.common.config.RuoYiConfig;
import io.minio.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import org.apache.http.entity.ContentType;
import java.io.*;
import java.lang.reflect.Modifier;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.zip.GZIPOutputStream;


@Component
public class MinioFileUtils {

    public static final String CHARSET = "ISO-8859-1";
    /**
     * FASTER_RCNN
     * eg: ckpt-19.data-00000-of-00001
     * **/
    public static final String FASTER_RCNN_EXT="data-";

    @Bean
    public MinioClient minioClient(RuoYiConfig humanResourcesProperty) {
        RuoYiConfig.Minio minio = humanResourcesProperty.getMinio();
        // 使用MinIO服务的URL，端口，Access key和Secret key创建一个MinioClient对象
        //MinioClient minioClient =MinioClient.builder(). MinioClient.builder().endpoint(minio.getEndpoint(), minio.getPort(), minio.getHttps())
        //  .credentials(minio.getAccessKey(), minio.getSecretKey()).build();
        MinioClient minioClient = MinioClient.builder().endpoint(minio.getEndpoint()).credentials(minio.getAccessKey(), minio.getSecretKey()).build();
        try {
            minioClient.ignoreCertCheck();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return minioClient;
    }

    @Autowired
    private MinioClient minioClient;
    @Autowired
    private RuoYiConfig humanResourcesProperty;
    private static GsonBuilder gsonBuilder = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss");
    private final static Gson gson = gsonBuilder.disableHtmlEscaping()
            .excludeFieldsWithModifiers(Modifier.PROTECTED, Modifier.TRANSIENT, Modifier.STATIC).create();
    private static final Logger logger = LoggerFactory.getLogger(MinioFileUtils.class);
    // public static final String CHARSET = "ISO-8859-1";

    public static String GZIP(String filePath) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {

            String json = FileUtils.readFileToString(new File(filePath), CHARSET);
            GZIPOutputStream gos = new GZIPOutputStream(bos);
            gos.write(json.getBytes(CHARSET));
            gos.close();
            return bos.toString(CHARSET);
        } catch (IOException var3) {
            System.out.println(var3.getStackTrace().toString());
            return null;
        }

    }


    public Result checkImg(MultipartFile file) {
        return checkFile(file, true);
    }

    public Result checkFile(MultipartFile file) {
        return checkFile(file, false);
    }

    public Result checkFile(MultipartFile file, Boolean isImg) {
        if (file == null)
            return Result.FAIL(humanResourcesProperty.getMessage().getEmptyFile());

        String fileExt = FilenameUtils.getExtension(file.getOriginalFilename());
        if (isImg) {
            if (!isAllowedImgExt(fileExt))
                return Result.FAIL(humanResourcesProperty.getMessage().getNotAllowedExt());
        } else {
            if (!isAllowedExt(fileExt))
                return Result.FAIL(humanResourcesProperty.getMessage().getNotAllowedExt());
        }
        if (!isAllowSize(file.getSize()))
            return Result.FAIL(humanResourcesProperty.getMessage().getNotAllowedSize());

        return Result.SUCCESS();
    }

    public Result checkFile(File file, Boolean isImg) {
        if (file == null)
            return Result.FAIL(humanResourcesProperty.getMessage().getEmptyFile());

        String fileExt = FilenameUtils.getExtension(file.getAbsolutePath());
        if (isImg) {
            if (!isAllowedImgExt(fileExt))
                return Result.FAIL(humanResourcesProperty.getMessage().getNotAllowedExt());
        } else {
            if (!isAllowedExt(fileExt))
                return Result.FAIL(humanResourcesProperty.getMessage().getNotAllowedExt());
        }
        if (!isAllowSize(file.length()))
            return Result.FAIL(humanResourcesProperty.getMessage().getNotAllowedSize());

        return Result.SUCCESS();
    }

    public Boolean isAllowedExt(String ext) {
        if (StringUtils.isEmpty(ext))
            return false;
        String[] exts = humanResourcesProperty.getMinio().getIncludeFileExts();
        for (int i = 0; i < exts.length; i++) {
            if (exts[i].toLowerCase().equals(ext.toLowerCase())) {
                return true;
            }
        }
        ///ckpt-19.data-00000-of-00001
        if(ext.startsWith(FASTER_RCNN_EXT)){
            return true;
        }
        return false;
    }

    public Boolean isAllowedImgExt(String ext) {
        if (StringUtils.isEmpty(ext))
            return false;
        String[] exts = humanResourcesProperty.getMinio().getIncludeImgExts();
        for (int i = 0; i < exts.length; i++) {
            if (exts[i].toLowerCase().equals(ext.toLowerCase())) {
                return true;
            }
        }
        return false;
    }

    public Boolean isAllowSize(Long size) {
        return size <= humanResourcesProperty.getMinio().getMaxSize() ? true : false;

    }

    public Result uploadImg(String base64Img) {
        if (StringUtils.isEmpty(base64Img))
            return Result.FAIL();
        String saveName = getDefaultImgName();
//        FileProperty fileProperty=new FileProperty();
//        fileProperty.setStorePath(saveName);
//        return Result.SUCCESS(fileProperty);
        return uploadImg(base64Img, saveName);
    }

    public Result uploadImg(String base64Img, String saveName) {
        InputStream inputStream = null;
        try {
            byte[] bytes = Base64.getDecoder().decode(base64Img);
            inputStream = new ByteArrayInputStream(bytes);
        } catch (Exception ex) {
            ex.printStackTrace();
            return Result.FAIL("上传失败");
        }

        return upload(MinioSaveTypeEnum.HEAD, inputStream, saveName, ContentType.IMAGE_JPEG.getMimeType());
    }

    public Result uploadImg(MinioSaveTypeEnum minioSaveType, InputStream inputStream, String saveName) {
        return upload(minioSaveType, inputStream, saveName, ContentType.IMAGE_JPEG.getMimeType());
    }

    public Result uploadFile(MinioSaveTypeEnum minioSaveType, InputStream inputStream, String saveName) {
        return upload(minioSaveType, inputStream, saveName, ContentType.APPLICATION_OCTET_STREAM.getMimeType());
    }

    /**
     * 默认 false
     **/
    public Result uploadFile(File file, MinioSaveTypeEnum minioSaveTypeEnum) throws IOException {
        if (file == null)
            return Result.FAIL(humanResourcesProperty.getMessage().getEmptyFile());

        Result result = checkFile(file, false);
        if (result.getCode() == Constant.FAIL_) {
            logger.error("uploadFile 失败:{}", gson.toJson(result));
            return result;
        }
        InputStream stream = new FileInputStream(file);// file.getInputStream();
        String fileExt = FilenameUtils.getExtension(file.getAbsolutePath());
        String orgName = FilenameUtils.getName(file.getAbsolutePath());
        String name = Utils.UUIDGenerat("");
        String newName = String.format("%s.%s", name, fileExt);

        result = upload(minioSaveTypeEnum, stream, newName, ContentType.APPLICATION_OCTET_STREAM.getMimeType());
        logger.info("uploadFile result:{}", gson.toJson(result));
        if (result.getCode() == Constant.SUCCESS_) {
            FileProperty fileProperty = (FileProperty) result.getData();
            fileProperty.setUniqueName(name);
            fileProperty.setImageName(orgName);
            fileProperty.setOrgPath(file.getAbsolutePath());
        }
        return result;
    }

    /**
     * inputStream 转化成 bytes
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] inputStreamToBytes(InputStream inputStream) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buff = new byte[4096];
        int index = 0;
        while ((index = inputStream.read(buff, 0, 4096)) > 0) {
            byteArrayOutputStream.write(buff, 0, index);
        }
        byte[] bytes = byteArrayOutputStream.toByteArray();
        if (byteArrayOutputStream != null) {
            byteArrayOutputStream.flush();
            byteArrayOutputStream.close();
        }
        return bytes;
    }


    /**
     * 默认 false
     **/
    public Result upload(MultipartFile file, Boolean isImg) throws IOException {
        if (file == null || file.isEmpty())
            return Result.FAIL(humanResourcesProperty.getMessage().getEmptyFile());

        Result result = checkFile(file, isImg);
        if (result.getCode() == Constant.FAIL_) {
            return result;
        }
        InputStream stream = file.getInputStream();
        String fileExt = FilenameUtils.getExtension(file.getOriginalFilename());
        String orgName = FilenameUtils.getName(file.getOriginalFilename());
        String name = Utils.UUIDGenerat("");
        String newName = String.format("%s.%s", name, fileExt);
        result = upload(MinioSaveTypeEnum.HEAD, stream, newName, file.getContentType());
        if (result.getCode() == Constant.SUCCESS_) {
            FileProperty fileProperty = (FileProperty) result.getData();
            fileProperty.setUniqueName(name);
            fileProperty.setImageName(orgName);
        }
        return result;
    }

    public Result upload(MinioSaveTypeEnum minioSaveType, InputStream inputStream, String saveName, String contentType) {
        RuoYiConfig.Minio minio = humanResourcesProperty.getMinio();

        String filePath = null;

        switch (minioSaveType) {
            case HEAD:
                filePath = minioSaveType.getPath();
                break;
            default:
                return Result.FAIL("未找到的SaveType");

        }
        String fullPath = String.format("%s%s%s", minio.getBucketName(), filePath, saveName);
        logger.info("upload 文件全路径:{}", fullPath);
        String savePath = String.format("%s%s", filePath, saveName);
        try {
            Long size = (long) inputStream.available();
            FileProperty fileProperty = new FileProperty();
            fileProperty.setImagePath(fullPath);
            fileProperty.setSize(size);
            if (saveName.contains(Constant.DEFAULT_EXT_SPLIT)) {
                Integer index = saveName.lastIndexOf(Constant.DEFAULT_EXT_SPLIT);
                String ext = saveName.substring(index);
                fileProperty.setExt(ext);
            }
            if (minioSaveType == MinioSaveTypeEnum.HEAD) {
                fileProperty.setHttpPath(minio.getStaticImageServer());
                fileProperty.setFullPath(String.format("%s%s", minio.getStaticImageServer(), fullPath));
            }

            BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                    .bucket(minio.getBucketName())
                    .build();
            // 检查存储桶是否已经存在
            boolean isExist = minioClient.bucketExists(bucketExistsArgs);
            if (!isExist) {
                MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                        .bucket(minio.getBucketName())
                        .build();
                minioClient.makeBucket(makeBucketArgs);
            }
//            String fileExt = FilenameUtils.getExtension(file.getOriginalFilename());
//            String orgName = FilenameUtils.getName(file.getOriginalFilename());

            logger.info("upload savepath:{}", savePath);
            Result result = uploadStream(inputStream, minio.getBucketName(), savePath, contentType);
            logger.info("upload result-uploadStream:{}", gson.toJson(result));
            if (result.getCode() == Constant.FAIL_) {
                return result;
            }
            result.setData(fileProperty);
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return Result.FAIL("文件上传失败");
    }

    /**
     * @param inputStream: 输入流
     * @param bucketName:  桶
     * @param savePath     :存储的位置
     * @return void
     * @Description 将图片上传到minio服务器
     **/
    public Result uploadStream(InputStream inputStream, String bucketName, String savePath, String contentType) {
        try {
            logger.info("uploadStream");
            long size = inputStream.available();
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(savePath)
                    .stream(inputStream, size, -1)
                    .contentType(contentType)
                    .build();
            minioClient.putObject(putObjectArgs);
            logger.info("uploadStream 成功");
            return Result.SUCCESS();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return Result.FAIL();
    }

    public String getDefaultImgName() {
        return String.format("%s.%s", Utils.UUIDGenerat(""), "jpg");
    }
}
